package com.hyt.it.ogt.ks.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hyt.it.ogt.ks.mapper.PaperTopicMapper;
import com.hyt.it.ogt.ks.model.entity.CandidateAnswer;
import com.hyt.it.ogt.ks.model.entity.CandidatePaper;
import com.hyt.it.ogt.ks.model.entity.PaperTopic;
import com.hyt.it.ogt.ks.model.vo.AnswerProgressVO;
import com.hyt.it.ogt.ks.service.ICandidateAnswerService;
import com.hyt.it.ogt.ks.service.ICandidatePaperService;
import com.hyt.it.ogt.ks.util.KeyDefineCommon;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.hyt.core.base.BaseServiceImpl;
import com.hyt.it.ogt.ks.mapper.AnswerProgressMapper;
import com.hyt.it.ogt.ks.model.entity.AnswerProgress;
import com.hyt.it.ogt.ks.service.IAnswerProgressService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author liuhenghuo
 */
@Slf4j
@Service
public class AnswerProgressServiceImpl extends BaseServiceImpl<AnswerProgressMapper, AnswerProgress>
        implements IAnswerProgressService {

    @Resource
    private ICandidatePaperService iCandidatePaperService;
    @Resource
    private PaperTopicMapper paperTopicMapper;
    @Resource
    private ICandidateAnswerService iCandidateAnswerService;
    @Resource
    private RedisTemplate redisTemplate;


    @Override
    public int saveItem(AnswerProgress answerProgress) {
        return baseMapper.saveItem(answerProgress);
    }

    /**
     * 返回对应考生的某一题的使用过了多少时长
     * @param examId
     * @param candidateId
     * @param paperSort
     * @return
     */
    @Override
    public Long getByExamIdAndCandidateId(String examId,String candidateId,Integer paperSort,String itemId,String childItemId){
        LambdaQueryWrapper<AnswerProgress> query = Wrappers.lambdaQuery();
        query.select(AnswerProgress::getAnswerTime).eq(AnswerProgress::getExamId, examId)
                .eq(AnswerProgress::getCandidateId, candidateId).eq(AnswerProgress::getPaperSort, paperSort)
                .eq(AnswerProgress::getItemId,itemId)
                .eq(AnswerProgress::getDelFlag,Boolean.FALSE)
                .orderByDesc(AnswerProgress::getUpdateDate).last("limit 1");
        if(StringUtils.isNotBlank(childItemId)){
            query.eq(AnswerProgress::getChildItemId,childItemId);
        }
        AnswerProgress record = this.baseMapper.selectOne(query);
        if(Objects.nonNull(record)){
            return Objects.nonNull(record.getAnswerTime()) ? record.getAnswerTime() : 0L;
        }
        return 0L;
    }

    /**
     * 重置答题时长撤销交卷时
     * @param examId
     * @param candidateId
     * @param candidatePaperId
     * @return
     */
    @Override
    public Boolean resetAnswerTimeCancelPaper(String examId, String candidateId, String candidatePaperId){
        //当没有传candidatePaperId时说明这个时候是单体试卷，考生只会有一个试卷
        if(Objects.isNull(candidatePaperId)){
            //查考生试卷
            LambdaQueryWrapper<CandidatePaper> paperQuery = Wrappers.lambdaQuery();
            paperQuery.select(CandidatePaper::getPaperId,CandidatePaper::getMixSort);
            paperQuery.eq(CandidatePaper::getExamId,examId).eq(CandidatePaper::getCandidateId,candidateId).last("LIMIT 1");
            CandidatePaper one = iCandidatePaperService.getOne(paperQuery);
            if(Objects.nonNull(one)){
                return clearCandidateProcess(examId,candidateId,one.getMixSort(),one.getPaperId(),Boolean.FALSE);
            }
            return Boolean.FALSE;
        }
        CandidatePaper paper = iCandidatePaperService.getById(candidatePaperId);
        if(Objects.nonNull(paper)){
            return clearCandidateProcess(examId,candidateId,paper.getMixSort(),paper.getPaperId(),Boolean.FALSE);
        }
        return Boolean.FALSE;
    }

    /**
     * 清理考生某一个试卷的进度
     *
     * @param examId
     * @param candidateId
     * @param paperSort
     * @param paperId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean clearCandidateProcess(String examId, String candidateId, Integer paperSort, String paperId,Boolean needFlag){
        String key = KeyDefineCommon.getCandidateResatTime(examId,candidateId);
        try {
            //先去查考生的paperSort
            LambdaQueryWrapper<CandidatePaper> paperQuery = Wrappers.lambdaQuery();
            paperQuery.eq(CandidatePaper::getCandidateId,candidateId).eq(CandidatePaper::getExamId,examId).eq(CandidatePaper::getSort,paperSort);
            paperQuery.select(CandidatePaper::getMixSort).last("LIMIT 1");
            CandidatePaper candidatePaper = iCandidatePaperService.getOne(paperQuery);
            LambdaUpdateWrapper<AnswerProgress> update = Wrappers.lambdaUpdate();
            update.eq(AnswerProgress::getExamId,examId).eq(AnswerProgress::getCandidateId,candidateId)
                    .eq(AnswerProgress::getPaperSort,candidatePaper.getMixSort());
            update.set(AnswerProgress::getDelFlag,Boolean.TRUE);
            this.update(update);

            //清理考生的答题表中的记录时长
            LambdaUpdateWrapper<CandidateAnswer> updateAnswer = Wrappers.lambdaUpdate();
            updateAnswer.eq(CandidateAnswer::getExamId,examId).eq(CandidateAnswer::getCandidateId,candidateId)
                    .eq(CandidateAnswer::getPaperId,paperId);
            updateAnswer.set(CandidateAnswer::getAnswerTime,0L);
            //todo 确认是否要清理
            //iCandidateAnswerService.update(updateAnswer);
            //保存重置的redis标识,撤销胶卷时不需要这个标识，因为这个时候考生不可能在作答界面，没有定时保存这个说法
            if(Objects.equals(Boolean.TRUE,needFlag)){
                redisTemplate.opsForValue().set(key,1);
            }
            return Boolean.TRUE;
        } catch (Exception e){
            log.error("清理考生进度失败，考试id：【{}】,考生id:【{}】，试卷号:【{}】",examId,candidateId,paperSort,e);
            //如果清理报错则清理reids key
            redisTemplate.delete(key);
            return Boolean.FALSE;
        }
    }

    /**
     * 清理考生某一个试卷的进度  --- reids重置标识
     *
     * @param examId
     * @param candidateId
     * @return
     */
    @Override
    public Boolean clearCandidateProcessRedisKey(String examId, String candidateId){
        String key = KeyDefineCommon.getCandidateResatTime(examId,candidateId);
        try {
            redisTemplate.delete(key);
        } finally {
            redisTemplate.delete(key);
            return Boolean.TRUE;
        }
    }

    /**
     * 获取当前题进度
     * @param examId
     * @param candidateId
     * @param paperSort
     * @return
     */
    @Override
    public AnswerProgressVO getCurrentItem(String examId, String candidateId, Integer paperSort){
        AnswerProgressVO answerProgressVO = new AnswerProgressVO();
        AnswerProgress one = this.lambdaQuery().eq(AnswerProgress::getExamId, examId)
                .eq(AnswerProgress::getCandidateId, candidateId).eq(AnswerProgress::getPaperSort, paperSort)
                .eq(AnswerProgress::getDelFlag,Boolean.FALSE)
                .orderByDesc(AnswerProgress::getUpdateDate).last("limit 1").one();
        if(one != null) {
            BeanUtils.copyProperties(one, answerProgressVO);
            //剩余时长
            //Long surplusTime = one.getOutTimeSecond() - one.getAnswerTime();surplusTime = surplusTime < 0 ? 0 : surplusTime;
            //answerProgressVO.setSurplusTime(surplusTime);
        } else {
            CandidatePaper paper = iCandidatePaperService.lambdaQuery().eq(CandidatePaper::getExamId, examId)
                    .eq(CandidatePaper::getCandidateId, candidateId).eq(CandidatePaper::getMixSort, paperSort).one();
            LambdaQueryWrapper<PaperTopic> query = Wrappers.<PaperTopic>lambdaQuery()
                    .eq(PaperTopic::getCandidatePaperId, paper.getId()).eq(PaperTopic::getSort, 1);
            PaperTopic paperTopic = paperTopicMapper.selectOne(query);
            answerProgressVO.setTopicId(paperTopic.getTopicId());
            answerProgressVO.setTopicSort(1);
            CandidateAnswer item = iCandidateAnswerService.lambdaQuery()
                    .select(CandidateAnswer::getItemType, CandidateAnswer::getItemId)
                    .eq(CandidateAnswer::getExamId, examId).eq(CandidateAnswer::getCandidateId, candidateId)
                    .eq(CandidateAnswer::getTopicId, paperTopic.getTopicId())
                    .and(a -> a.isNull(CandidateAnswer::getParentItemId).or()
                            .eq(CandidateAnswer::getParentItemId, ""))
                    .eq(CandidateAnswer::getItemMixSort, 1).one();
            answerProgressVO.setItemId(item.getItemId());
            answerProgressVO.setItemSort(1);
            answerProgressVO.setAnswerTime(0L);
            //计算及判断是否单题限时
            //Long outTimeSecond = (Objects.isNull(item.getOutTimeSecond()) || item.getOutTimeSecond() == 0) ? null : item.getOutTimeSecond();
            //answerProgressVO.setSurplusTime(outTimeSecond);
            CandidateAnswer childItem = iCandidateAnswerService.lambdaQuery()
                    .select(CandidateAnswer::getItemId)
                    .eq(CandidateAnswer::getExamId, examId)
                    .eq(CandidateAnswer::getCandidateId, candidateId)
                    .eq(CandidateAnswer::getTopicId, paperTopic.getTopicId())
                    .eq(CandidateAnswer::getParentItemId, item.getItemId())
                    .eq(CandidateAnswer::getItemMixSort, 1).one();
            if(childItem != null) {
                //计算及判断是否单题限时
                //Long childItemOutTimeSecond = (Objects.isNull(childItem.getOutTimeSecond()) || childItem.getOutTimeSecond() == 0) ? null : childItem.getOutTimeSecond();
                //answerProgressVO.setSurplusTime(childItemOutTimeSecond);
                answerProgressVO.setChildItemSort(1);
                answerProgressVO.setChildItemId(childItem.getItemId());
            }
        }
        return answerProgressVO;
    }

    /**
     * 保存答题进度
     * @return
     */
    @Override
    public void saveCurrentItem(AnswerProgress answerProgress){
        //判断一下是否有做重置
        String key = KeyDefineCommon.getCandidateResatTime(answerProgress.getExamId(),answerProgress.getCandidateId());
        if(redisTemplate.hasKey(key)){
            return;
        }
        AnswerProgress one = this.lambdaQuery().select(AnswerProgress::getId,AnswerProgress::getAnswerTime
                        ,AnswerProgress::getItemId,AnswerProgress::getChildItemId)
                .eq(AnswerProgress::getExamId, answerProgress.getExamId())
                .eq(AnswerProgress::getCandidateId, answerProgress.getCandidateId())
                .eq(AnswerProgress::getPaperSort, answerProgress.getPaperSort())
                .eq(AnswerProgress::getDelFlag,Boolean.FALSE)
                .last("limit 1").orderByDesc(AnswerProgress::getId).one();
        LocalDateTime now = LocalDateTime.now();
        if(one != null) {
            answerProgress.setId(one.getId());
            answerProgress.setUpdateDate(now);
            //进度的值不能变,如查试题id一样的情况下
            if(Objects.equals(answerProgress.getItemId(),one.getItemId())
                    && ((StringUtils.isBlank(one.getChildItemId()) && StringUtils.isBlank(answerProgress.getChildItemId()))
                    || Objects.equals(answerProgress.getChildItemId(),one.getChildItemId()))){
                answerProgress.setAnswerTime(one.getAnswerTime());
            } else {
                answerProgress.setAnswerTime(0L);
            }
            this.updateById(answerProgress);
        } else {
            answerProgress.setCreateDate(now);
            answerProgress.setUpdateDate(now);
            this.save(answerProgress);
        }
    }

    /**
     * 定时保存答题进度
     * @return
     */
    public Map<String,Boolean> timingSaveItem(AnswerProgress answerProgress){
        Map<String,Boolean> map = new HashMap<>();
        //判断一下是否有做重置
        String key = KeyDefineCommon.getCandidateResatTime(answerProgress.getExamId(),answerProgress.getCandidateId());
        if(redisTemplate.hasKey(key)){
            map.put("isReset",Boolean.TRUE);
            return map;
        }
        AnswerProgress one = this.lambdaQuery().select(AnswerProgress::getId,AnswerProgress::getAnswerTime
                        ,AnswerProgress::getItemId,AnswerProgress::getChildItemId)
                .eq(AnswerProgress::getExamId, answerProgress.getExamId())
                .eq(AnswerProgress::getCandidateId, answerProgress.getCandidateId())
                .eq(AnswerProgress::getPaperSort, answerProgress.getPaperSort())
                .eq(AnswerProgress::getDelFlag,Boolean.FALSE)
                .last("limit 1").orderByDesc(AnswerProgress::getId).one();
        LocalDateTime now = LocalDateTime.now();
        if(one != null) {
            answerProgress.setId(one.getId());
            answerProgress.setUpdateDate(now);
            Long answerTime = NumberUtils.toLong(String.valueOf(one.getAnswerTime()),0L) + answerProgress.getAnswerTime();
            //进度的值不能变,如查试题id一样的情况下
            if(Objects.equals(answerProgress.getItemId(),one.getItemId())
                    && ((StringUtils.isBlank(one.getChildItemId()) && StringUtils.isBlank(answerProgress.getChildItemId()))
                    || Objects.equals(answerProgress.getChildItemId(),one.getChildItemId()))){
                answerProgress.setAnswerTime(answerTime);
            } else {
                Long time = NumberUtils.toLong(String.valueOf(answerProgress.getAnswerTime()),0L);
                answerProgress.setAnswerTime(time);
            }
            this.updateById(answerProgress);
        } else {
            answerProgress.setCreateDate(now);
            answerProgress.setUpdateDate(now);
            this.save(answerProgress);
        }
        map.put("isReset",Boolean.FALSE);
        return map;
    }
}
